﻿using System;
using System.Drawing;
using System.IO;
using NPOI.HSSF.UserModel;
using NPOI.HSSF.Util;
using NPOI.SS.UserModel;
using NPOI.SS.Util;
using NPOI.XSSF.UserModel;

namespace Sys.Excel
{
    public sealed class NPOI_ExcelExporter : ExcelExporterBase<IWorkbook, ISheet, ICellStyle>
    {
        #region [ private ]

        private HSSFColor Get_HSSFColor(HSSFWorkbook workbook, Color color)
        {
            HSSFPalette palette = workbook.GetCustomPalette();
            HSSFColor colour = palette.FindColor(color.R, color.G, color.B);
            if (colour == null) { colour = palette.FindSimilarColor(color.R, color.G, color.B); }
            if (colour == null) { try { colour = palette.AddColor(color.R, color.G, color.B); } catch { } }
            return colour;
        }

        private ICell Get_Cell(ISheet sheet, int row, int col)
        {
            IRow sheet_row = sheet.GetRow(row);
            if (sheet_row == null) { sheet_row = sheet.CreateRow(row); sheet_row.Height = 400; }
            return sheet_row.GetCell(col) ?? sheet_row.CreateCell(col);
        }

        #endregion

        #region [ ExcelExporterBase<IWorkbook, ISheet> ]

        protected override IWorkbook CreateWorkBook(bool useOldVersion)
        {
            return useOldVersion ?
                (IWorkbook)new HSSFWorkbook() : (IWorkbook)new XSSFWorkbook();
        }

        protected override ISheet CreateWorkSheet(IWorkbook workbook, string name, Settings settings)
        {
            return name == null ? workbook.CreateSheet() : workbook.CreateSheet(name);
        }

        protected override ICellStyle CreateCellStyle(IWorkbook workbook, ICellStyle style, CellStyle cellStyle)
        {
            style = workbook.CreateCellStyle();

            HorizontalAlignment h_align = HorizontalAlignment.Center;
            Enum.TryParse<HorizontalAlignment>(cellStyle.TextAlign.ToString(), out h_align);
            style.Alignment = h_align;

            style.VerticalAlignment = VerticalAlignment.Center;

            FontBoldWeight weight = FontBoldWeight.Normal;
            IFont font = workbook.CreateFont();
            Enum.TryParse<FontBoldWeight>(cellStyle.FontWeight.ToString(), out weight);
            font.Boldweight = (short)weight;
            if (font is HSSFFont)
            {
                font.Color = (this.Get_HSSFColor((HSSFWorkbook)workbook, cellStyle.FgColor) ?? new HSSFColor.White()).Indexed;
            }
            else if (font is XSSFFont)
            {
                (font as XSSFFont).SetColor(new XSSFColor(cellStyle.FgColor));
            }
            style.SetFont(font);

            style.FillPattern = FillPattern.SolidForeground;

            if (style is HSSFCellStyle)
            {
                style.FillForegroundColor = (this.Get_HSSFColor((HSSFWorkbook)workbook, cellStyle.BgColor) ?? new HSSFColor.White()).Indexed;
            }
            else if (style is XSSFCellStyle)
            {
                (style as XSSFCellStyle).FillForegroundColorColor = new XSSFColor(cellStyle.BgColor);
            }

            style.BorderLeft = BorderStyle.Thin;
            style.BorderTop = BorderStyle.Thin;
            style.BorderRight = BorderStyle.Thin;
            style.BorderBottom = BorderStyle.Thin;

            return style;
        }

        protected override ICellStyle GetCellStyle(
            IWorkbook workbook, ISheet sheet, int row, int col)
        {
            return this.Get_Cell(sheet, row, col).CellStyle;
        }

        protected override void SetCell(
            IWorkbook workbook, ISheet sheet, int row,
            int col, Settings settings, ColNode node, object value, ICellStyle style,
            bool setValue = true, bool setStyle = true)
        {
            if (setValue || setStyle)
            {
                ICell sheet_cell = this.Get_Cell(sheet, row, col);
                if (setValue) sheet_cell.SetCellValue(value == null ? null : value.ToString());
                if (setStyle) sheet_cell.CellStyle = style;
            }
        }

        protected override void MergeCells(
            IWorkbook workbook, ISheet sheet, int startRow,
            int endRow, int startCol, int endCol, Settings settings)
        {
            sheet.AddMergedRegion(new CellRangeAddress(startRow, endRow, startCol, endCol));
        }

        protected override void FreezePane(
            IWorkbook workbook, ISheet sheet, int rowSplit, int colSplit)
        {
            sheet.CreateFreezePane(colSplit, rowSplit);
        }

        protected override void SetColumnsWidth(
            IWorkbook workbook, ISheet sheet, Settings settings, uint[] widthArray, int startCol)
        {
            for (int i = 0; i < settings.LeafNodes.Count; i++)
            {
                sheet.SetColumnWidth(startCol + i, (int)widthArray[i] * 256);
            }
        }

        protected override void AutoFillColumns(
            IWorkbook workbook, ISheet sheet, Settings settings, int startCol)
        {
            for (int i = 0; i < settings.LeafNodes.Count; i++)
            {
                sheet.AutoSizeColumn((int)startCol + i, true);
            }
        }

        protected override void Save(IWorkbook workbook, bool useOldVersion, Stream stream)
        {
            workbook.Write(stream);
            workbook.Close();
        }

        #endregion
    }
}